// Copyright (c) 2010, Anthony Cassidy
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are 
// permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice, this list 
//         of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//         list of conditions and the following disclaimer in the documentation and/or 
//         other materials provided with the distribution.
//     * Neither the name of the AntsAdventureGameCreator nor the names of its contributors 
//         may be used to endorse or promote products derived from this software without 
//         specific prior written permission.
// 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
// THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include "XStdafx.h"
#include "RoomObject.h"
#include "Choices.h"
extern QThread* g_guiThread;

// By defining the slots as virtual {}, then anyone wanting to be subscribed to the signals
// doesn't even need to declare any signals, nor implement any unneccessary functions
// It does mean, however, that the emitter fires tens of unnexcessary signals
// Every time it runs a script: Make virtual, connect everything to everything, then run.
// So as an optmisation, make XEmitter constructor connect conditionally, depending on
// type of receiver,
//
#define ECONNECT(x) CONNECT(this,SIGNAL(x),receiver,SLOT(x),Qt::QueuedConnection);
#define RCONNECT(x) CONNECT(receiver,SIGNAL(x),this,SLOT(x),Qt::QueuedConnection);

class XReceiver : public QObject
{
    Q_OBJECT;
protected:
    static bool m_isBlocking;
    static bool m_isSayingAbort;
public:
    XReceiver();
    static int IsBlocking();
    static int IsSayingAbort();
    static void SetIsSayingAbort(bool isSayingAbort);
    static void SetBlocking(bool isBlocking);
 public slots:

    virtual void  timerEvent(QTimerEvent*){};

    virtual void SetVisible(bool){};
    virtual void SetDisplayName(QString){};
    virtual void SetX(int){};
    virtual void SetY(int){};
    virtual void SetCurrentAnimationName(QString){};
    virtual void SetCurrentAnimationFrameIndex(int){};
    virtual void Clear(){};
    virtual void SetMouseable(bool){};
    virtual void SetTalkingAnimationName(QString str){};
    virtual void Say(QString){};
    virtual void SetDefaultVerb(int, QString verbWithObjectMask){};
    virtual void UpdateRects(){};
    virtual void PreloadAnimation(QString animKeyword){};
    virtual void IncrementFrame(){};
    virtual void SetAsCurrentAnimation(){};
    virtual void SetAsTalkingAnimation(){};
    virtual void PreloadAnimation(){};
    virtual void SetTalkingDelay(int){}
    virtual void PlayAnimation(int){};
    virtual void PlayAnimation(QString,int){};
    virtual void PlayAnimationHoldLastFrame(int){};
    virtual void PlayAnimationHoldLastFrame(QString,int){};
    virtual void PlayAnimationRepeatWhilstVisible(int){};
    virtual void PlayAnimationRepeatWhilstVisible(QString,int){};
    virtual void PlayAnimationBackwards(int){};
    virtual void PlayAnimationBackwards(QString,int){};
    virtual void PlayAnimationBackwardsHoldLastFrame(int){};
    virtual void PlayAnimationBackwardsHoldLastFrame(QString,int){};
    virtual void UpdateImage(){};
    virtual void SayWithoutAnimation(QString speech){};
    virtual void MakeRoomActive(QString keyword){};
    virtual void WalkTo(int, int){}
    virtual void SetSpecialAnimation(SpecialAnimation, QString animKeyword){}
    virtual void Remove(QString){}
    virtual void AddNew(QString,QString){}
    virtual void SetAsSpecialAnimation(SpecialAnimation){}
    virtual void DoChoices(Choices){}
    virtual void SetTalkingColor(QString){}
    virtual void SetOrderingNumber(int){}
    virtual void SetEnableGive(bool){}
    //
    // Only need to add functions in three places..
    // 1. Declare receiver just above here ^
    //
};

class XEmitter : public XReceiver
{
    Q_OBJECT;
signals:
    void timerEvent(QTimerEvent* timer);
    void Clear() ;
    void SetVisible(bool visible);
    void SetDisplayName(QString displayName);
    void SetX(int);
    void SetY(int);
    void SetCurrentAnimationName(QString);
    void SetCurrentAnimationFrameIndex(int);
    void SetMouseable(bool mousable);
    void Say(QString);
    void SetTalkingAnimationName(QString str);
    void SetDefaultVerb(int i, QString verbWithObjectMask);
    void UpdateRects();
    void PreloadAnimation(QString animKeyword);
    void IncrementFrame();
    void SetAsCurrentAnimation();
    void SetAsTalkingAnimation();
    void PreloadAnimation();
    void SetTalkingDelay(int i);
    void PlayAnimation(int delay=0);
    void PlayAnimation(QString,int delay=0);
    void PlayAnimationHoldLastFrame(int delay=0);
    void PlayAnimationHoldLastFrame(QString,int delay=0);
    void PlayAnimationRepeatWhilstVisible(int delay=0);
    void PlayAnimationRepeatWhilstVisible(QString,int delay=0);
    void UpdateImage();
    void PlayAnimationBackwards(int delay=0);
    void PlayAnimationBackwards(QString,int delay=0);
    void PlayAnimationBackwardsHoldLastFrame(int delay=0);
    void PlayAnimationBackwardsHoldLastFrame(QString,int delay=0);
    void SayWithoutAnimation(QString speech);
    void MakeRoomActive(QString keyword);
    void WalkTo(int x, int y);
    void SetSpecialAnimation(SpecialAnimation, QString animKeyword);
    void Remove(QString keyword);
    void AddNew(QString keyword,QString sentenceTemplate);
    void SetAsSpecialAnimation(SpecialAnimation);
    void DoChoices(Choices ch);
    void SetTalkingColor(QString color);
    void SetOrderingNumber(int orderingNumber);
    void SetEnableGive(bool isGiveEnabled);
    //
    // 2. ... Declare sender just above here ^
    //

public:
    XEmitter(XReceiver* receiver):m_nonMarshallingCallbacks(receiver)
    {
        XEmitter::QObject::disconnect(this,0);
        ECONNECT(SetVisible(bool));
        ECONNECT(Clear());
        ECONNECT(SetDisplayName(QString));
        ECONNECT(Say(QString));
        ECONNECT(SetX(int));
        ECONNECT(SetY(int));
        ECONNECT(SetCurrentAnimationName(QString));
        ECONNECT(SetCurrentAnimationFrameIndex(int));
        ECONNECT(SetMouseable(bool));
        ECONNECT(SetTalkingAnimationName(QString));
        ECONNECT(SetDefaultVerb(int,QString));
        ECONNECT(UpdateRects());
        ECONNECT(PreloadAnimation(QString));
        ECONNECT(IncrementFrame());
        ECONNECT(SetAsCurrentAnimation());
        ECONNECT(SetAsTalkingAnimation());
        ECONNECT(PreloadAnimation());
        ECONNECT(SetTalkingDelay(int));
        ECONNECT(PlayAnimation(int));
        ECONNECT(PlayAnimation(QString,int));
        ECONNECT(PlayAnimationHoldLastFrame(int));
        ECONNECT(PlayAnimationHoldLastFrame(QString,int));
        ECONNECT(PlayAnimationRepeatWhilstVisible(int));
        ECONNECT(PlayAnimationRepeatWhilstVisible(QString,int));
        ECONNECT(UpdateImage());
        ECONNECT(PlayAnimationBackwards(int));
        ECONNECT(PlayAnimationBackwards(QString,int));
        ECONNECT(PlayAnimationBackwardsHoldLastFrame(int));
        ECONNECT(PlayAnimationBackwardsHoldLastFrame(QString,int));
        ECONNECT(SayWithoutAnimation(QString));
        ECONNECT(MakeRoomActive(QString));
        ECONNECT(WalkTo(int,int));
        ECONNECT(SetSpecialAnimation(SpecialAnimation,QString));
        ECONNECT(Remove(QString));
        ECONNECT(AddNew(QString,QString));
        ECONNECT(SetAsSpecialAnimation(SpecialAnimation));
        ECONNECT(DoChoices(Choices));
        ECONNECT(SetTalkingColor(QString));
        ECONNECT(SetOrderingNumber(int));
        ECONNECT(SetEnableGive(bool));
        //
        // 3. ...and finally, here ^, Connect 'em up!
        //
    }
    XEmitter();

public:
    // overloaded operator allows dynamic determination of whether to call directly or use signal
    XReceiver* GetReceiver();
    const XReceiver* operator->() const;
    bool IsBlocking() const;
    bool IsSayingAbort() const;
    friend class Animation;
    friend class Animations;
    friend class Room;
    friend class RoomObject;
    friend class RoomObjects;
    friend class Verbs;
    friend class Verb;
    friend class CommandLine;
    friend class Gui;
    friend class Inventory;
    friend class InventoryItem;
private:
    XReceiver* m_nonMarshallingCallbacks;
};
